#include "HD44780AnalyzerSettings.h"
#include <AnalyzerHelpers.h>
#include "Utilities.h"
#include "PluginConstants.h"
#include <windows.h>
#include <iostream>
//#include <shlobj.h>

static U32 LineValuesList[][3] = 
{ 
    {0,0,0},
    {0,0,1},
    {0,0,2},
    {0,0,3},
    {0,1,4},
    {1,2,5},
    {2,3,6},
    {3,4,7},
    {4,5,8},
    {5,6,9},
    {6,7,10}
};

static const char* OperatingModeNames[] = { "7 Bits", "8 Bits", "11 Bits" };

static const char* ChannelInfo[][2] =
{   
    {"Data 0", "Data 0 (Optional)"},
    {"Data 1", "Data 1 (Optional)"},
    {"Data 2", "Data 2 (Optional)"},
    {"Data 3", "Data 3 (Optional - Will enable 4 bit mode)"},
    {"Data 4", "Data 4"},
    {"Data 5", "Data 5"},
    {"Data 6", "Data 6"},
    {"Data 7", "Data 7 | (Busy Bit)"},
    {"Register Select (RS)","Register Select"},
    {"Register Read|Write (RW)","Register Read|Write (RW)"},
    {"Enable  (E)","Chip Enable"},
    { NULL, NULL }
};

static const char* OptionsForDataGeneration[][2] =
{   
    {"Data Generation", "Parameters to generate data" },  // First entry is Title and tooltip
    {"8|4 Bit Initialization Sequence", "Generate initialization sequence for 8 or 4 bits described on page 45/46 of HD44780 datasheet"},
    {"The Quick Brown Fox Jumps Over The Lazy Dog", "Generate message containing The Quick Brown Fox Jumps Over The Lazy Dog"},
    {"Generate message from text box", "Read content of text box"},
    { NULL, NULL }
};

static const char* OptionsForPositionToMeasurePulse[][2] =
{   
    {"Measure Position", "Location in CLOCK pulse where to measure channel values" }  // First entry is Title and tooltip
};


static const char* TextBoxSettings[][2] = 
{
    { "Generation Message", "Message to generate when the Generate message from text box option is selected" }
};     

static const char* DefaultText = "Hello World!";

static const char* ErrorMessage1 = "Invalid operating mode has been has been detected.  The same channel has been reuse multiple times.\n\n"
             "A channel can only be used once.\n\n"
             "See documentation distributed with the HD44780 protocol analyzer for more information";

static const char* ErrorMessage2 = "Invalid operating mode has been has been detected.  The HD44780 protocol analyzer supports the following modes.\n\n"
             "7 Bits: Channels Data 0 - Data 3 are not selected.  The HD44780 chip is programmed with 4 data lines. Requires Logic8/Logic16\n\n"
             "8 Bits: Channels Data 0 - Data 2 are not selected.  The HD44780 is programmed with 8 data lines.  Requires Logic8/Logic16\n\n"
             "11 Bits: All channels are selected.  The HD44870 chip is programmed with 8 data lines. Requires Logic16\n\n"
             
             "See documentation distributed with the HD44780 protocol analyzer for more information";

static const char* ErrorMessage3 = "Invalid operating mode has been has been detected.  Channels Data 3 - Data 7 and RS, RW and E must be defined.\n\n"
             "See documentation distributed with the HD44780 protocol analyzer for more information";

HD44780AnalyzerSettings::HD44780AnalyzerSettings()
    :mOptionForDataGenerator(0), mOperationMode(BITS8), mDataGenerationMode(BROWNFOX), mPositionWhereToMeasurePulse(DEFAULT_POS)
{
    CreateSettingsOptions();
    RegisterSettingOptionsWithOutsideWorld();
    ConfigureExportOptions();
    ReportChannelsToOutsideWorld();
}

HD44780AnalyzerSettings::~HD44780AnalyzerSettings()
{
	DeleteAllDataChannelInterfaces();
}

 HD44780AnalyzerSettings::OperationMode HD44780AnalyzerSettings::GetOperationMode()
 {
     return mOperationMode;
 }

HD44780AnalyzerSettings::DataGenerationMode HD44780AnalyzerSettings::GetDataGenerationMode()
{
    return mDataGenerationMode;
}

 Channel HD44780AnalyzerSettings::GetClock()
 {
     return mDataChannels[RE];
 }

 U32  HD44780AnalyzerSettings::GetDefinedChannelsCount()
 {
     return mDataChannels.size();
 }

 Channel HD44780AnalyzerSettings::GetDefinedChannel( U32 index )
 {
      return mDataChannels[index];
 }

bool HD44780AnalyzerSettings::AllOptionalChannelsAreUndefined()
{
    return ( mDataChannels[D0] == UNDEFINED_CHANNEL &&
          mDataChannels[D1] == UNDEFINED_CHANNEL &&
          mDataChannels[D2] == UNDEFINED_CHANNEL &&
          mDataChannels[D3] == UNDEFINED_CHANNEL ) ? true : false;
}

bool HD44780AnalyzerSettings::FirstThreeOptionalChannelsAreUndefined()
{
    return ( mDataChannels[D0] == UNDEFINED_CHANNEL &&
          mDataChannels[D1] == UNDEFINED_CHANNEL &&
          mDataChannels[D2] == UNDEFINED_CHANNEL ) ? true : false;
}

bool HD44780AnalyzerSettings::AnyOptionalChannelIsUndefined()
{
    return ( mDataChannels[D0] == UNDEFINED_CHANNEL ||
          mDataChannels[D1] == UNDEFINED_CHANNEL ||
          mDataChannels[D2] == UNDEFINED_CHANNEL ||
          mDataChannels[D3] == UNDEFINED_CHANNEL ) ? true : false;
}

bool HD44780AnalyzerSettings::AllRequiredChannelsAreDefined()
{
     bool result = true;
     for ( int i = D4; i <= RE; ++i )
     {
         if ( mDataChannels[i] == UNDEFINED_CHANNEL )
         {
             result = false;
             break;
         }
     }
     return result;
}

bool HD44780AnalyzerSettings::IsAnyChannelDefinedMoreThanOnce()
{
     bool Result = false;
     for ( int i = D0; i < RE; ++i )
     {
         if ( mDataChannels[i] == UNDEFINED_CHANNEL )
            continue;

         for ( int j = i+1; j <=RE; ++j )
         {
             if ( mDataChannels[j] == UNDEFINED_CHANNEL )
                 continue;
             if (  mDataChannels[j] ==  mDataChannels[i] )
             {
                 Result = true;
                 break;
             }
         }

         if ( Result )
             break;
     }
     return Result;
}

 bool HD44780AnalyzerSettings::CalculateOperatingMode()
 {
     bool Result = false;

     if ( !AllRequiredChannelsAreDefined() )
     {
         mOperationMode = HD44780AnalyzerSettings::INVALID;
         SetErrorText(ErrorMessage3);
     }
     else if ( IsAnyChannelDefinedMoreThanOnce() )
     {
         mOperationMode = HD44780AnalyzerSettings::INVALID;
         SetErrorText(ErrorMessage1);
     }
     else if ( AllOptionalChannelsAreUndefined() )
     {
        mOperationMode = HD44780AnalyzerSettings::BITS7;
        Result = true;
     }
     else if ( FirstThreeOptionalChannelsAreUndefined() )
     {
         mOperationMode = HD44780AnalyzerSettings::BITS8;
         Result = true;
     }
     else if (  AnyOptionalChannelIsUndefined() )
     {
         mOperationMode = HD44780AnalyzerSettings::INVALID;
         SetErrorText(ErrorMessage2);
     }
     else 
     {
        mOperationMode = HD44780AnalyzerSettings::BITS11;
        Result = true;
     }

     return Result;
 }
 
 void HD44780AnalyzerSettings::CalculateDataGenerationMode()
 {
     mDataGenerationMode = (DataGenerationMode)mOptionForDataGenerator;
 }

void HD44780AnalyzerSettings::CreateSettingsOptions()
{
    U32 ChannelIndex = 0;
    while ( ChannelInfo[ChannelIndex][CHANNEL_NAME] != NULL )
    {
        mDataChannels.push_back( UNDEFINED_CHANNEL );
        AnalyzerSettingInterfaceChannel* DataChannelInterface = new AnalyzerSettingInterfaceChannel();

        DataChannelInterface->SetTitleAndTooltip( ChannelInfo[ChannelIndex][CHANNEL_NAME] ,  ChannelInfo[ChannelIndex][CHANNEL_TOOLTIP] );
		DataChannelInterface->SetChannel( mDataChannels[ChannelIndex] );
        
        if ( ChannelIndex >= OPTIONAL_CHANNEL_BEGIN && ChannelIndex <= OPTIONAL_CHANNEL_END )
		    DataChannelInterface->SetSelectionOfNoneIsAllowed( true );

        mDataChannelsInterface.push_back( DataChannelInterface );
        ChannelIndex++;
    }

    Utilities::InitNumberList( mDataGenerationOptions, OptionsForDataGeneration, 0 );

    mPositionToMeasurePulseOptions.reset( new AnalyzerSettingInterfaceInteger() );
    mPositionToMeasurePulseOptions->SetTitleAndTooltip( OptionsForPositionToMeasurePulse[0][0], OptionsForPositionToMeasurePulse[0][1] );
    mPositionToMeasurePulseOptions->SetMin(MIN_POS);
    mPositionToMeasurePulseOptions->SetMax(MAX_POS);
    mPositionToMeasurePulseOptions->SetInteger(mPositionWhereToMeasurePulse);

    Utilities::InitNormalTextField( mGenerationText, TextBoxSettings, DefaultText );

    mTextForDataGenerator = mGenerationText->GetText();
}

void HD44780AnalyzerSettings::RegisterSettingOptionsWithOutsideWorld()
{
    const int MaxChannels = mDataChannelsInterface.size();
	for ( U32 i = 0; i < MaxChannels; ++i )
	{
		AddInterface( mDataChannelsInterface[i] );
	}

    AddInterface( mPositionToMeasurePulseOptions.get() );
    AddInterface( mDataGenerationOptions.get() );
    AddInterface( mGenerationText.get() );
}

void HD44780AnalyzerSettings::ConfigureExportOptions()
{
    AddExportOption( EXPORT_OPTION_CSV, "Export as text/csv file" );
    AddExportOption( EXPORT_OPTION_SEQ, "Export as Sequence Diagram file" );
	AddExportExtension( EXPORT_OPTION_CSV, "text", "txt" );
	AddExportExtension( EXPORT_OPTION_CSV, "csv", "csv" );
	AddExportExtension( EXPORT_OPTION_SEQ, "text", "txt" );
}

void HD44780AnalyzerSettings::ReportChannelsToOutsideWorld()
{
	ClearChannels();
    const int MaxChannels = mDataChannelsInterface.size();
	for ( U32 i = 0; i < MaxChannels; ++i )
	{
        AddChannel( mDataChannels[i], ChannelInfo[i][CHANNEL_NAME], false );
	}
}

bool HD44780AnalyzerSettings::SetSettingsFromInterfaces()
{
    const int MaxChannels = mDataChannelsInterface.size();
	for ( U32 i = 0; i < MaxChannels; ++i )
	{
		mDataChannels[i] = mDataChannelsInterface[i]->GetChannel();
	}
    ClearChannels();
	for ( U32 i = 0; i < MaxChannels; ++i )
	{
        AddChannel( mDataChannels[i], ChannelInfo[i][0], mDataChannels[i] != UNDEFINED_CHANNEL );
	}

    mPositionWhereToMeasurePulse = mPositionToMeasurePulseOptions->GetInteger();
    mOptionForDataGenerator =  mDataGenerationOptions->GetNumber();
    mTextForDataGenerator = mGenerationText->GetText();

    bool Result = CalculateOperatingMode();
    CalculateDataGenerationMode();
    return Result;
}

void HD44780AnalyzerSettings::UpdateInterfacesFromSettings()
{
	U32 count = mDataChannels.size();
	for( U32 i=0; i<count; i++ )
	{
		mDataChannelsInterface[i]->SetChannel( mDataChannels[i] );
	}

    mPositionToMeasurePulseOptions->SetInteger( mPositionWhereToMeasurePulse );
    mDataGenerationOptions->SetNumber(mOptionForDataGenerator);
    mGenerationText->SetText (  mTextForDataGenerator.c_str());
}

void HD44780AnalyzerSettings::LoadSettings( const char* settings )
{
    SimpleArchive text_archive;
    char Buffer[1024];
    char const* BufferPtr = (const char*)&Buffer;
	text_archive.SetString( settings );
    
	U32 count = mDataChannels.size();

	for( U32 i=0; i<count; i++ )
	{
		text_archive >> mDataChannels[i];
	}

    text_archive >> mPositionWhereToMeasurePulse;
    text_archive >> mOptionForDataGenerator;
    text_archive >>(&BufferPtr);
    mTextForDataGenerator = BufferPtr;

    ClearChannels();
	for( U32 i=0; i<count; i++ )
	{
        AddChannel( mDataChannels[i], ChannelInfo[i][0], true );
	}
	UpdateInterfacesFromSettings();
    CalculateOperatingMode();
    CalculateDataGenerationMode();
}

const char* HD44780AnalyzerSettings::SaveSettings()
{
    SimpleArchive text_archive;
    U32 count = mDataChannels.size();
    for( U32 i=0; i<count; i++ )
	{
		text_archive << mDataChannels[i];
	}

    text_archive << mPositionWhereToMeasurePulse;
    text_archive << mOptionForDataGenerator;
    text_archive << mTextForDataGenerator.c_str();

	return SetReturnString( text_archive.GetString() );
}

U32 HD44780AnalyzerSettings::GetData0()
{
    return LineValuesList[0][mOperationMode];
}

U32 HD44780AnalyzerSettings::GetData1()
{
   return LineValuesList[1][mOperationMode];
}

U32 HD44780AnalyzerSettings::GetData2()
{
   return LineValuesList[2][mOperationMode];
}

U32 HD44780AnalyzerSettings::GetData3()
{
  return LineValuesList[3][mOperationMode];
}

U32 HD44780AnalyzerSettings::GetData4()
{
   return LineValuesList[4][mOperationMode];
}

U32 HD44780AnalyzerSettings::GetData5()
{
   return LineValuesList[5][mOperationMode];
}

U32 HD44780AnalyzerSettings::GetData6()
{
   return LineValuesList[6][mOperationMode];
}

U32 HD44780AnalyzerSettings::GetData7()
{
   return LineValuesList[7][mOperationMode];
}

U32 HD44780AnalyzerSettings::GetRs()
{
   return LineValuesList[8][mOperationMode];
}

U32 HD44780AnalyzerSettings::GetRw()
{
   return LineValuesList[9][mOperationMode];
}

U32 HD44780AnalyzerSettings::GetRe()
{
   return LineValuesList[10][mOperationMode];
}

void HD44780AnalyzerSettings::DeleteAllDataChannelInterfaces()
{
	U32 count = mDataChannelsInterface.size();
	for( U32 i=0; i<count; i++ )
		delete mDataChannelsInterface[i];
}

const char* HD44780AnalyzerSettings::GetText()
{
    
    return ( GetDataGenerationMode() == TEXTBOX  ) ? mTextForDataGenerator.c_str() : OptionsForDataGeneration[2][0];
}

const char* HD44780AnalyzerSettings::GetModeName()
{
    return OperatingModeNames[mOperationMode];
}